#pragma once

#include "node.h"
#include "Token.h"
#include "Expression.h"

class AssignmentClause: public Clause
{
public:
    AssignmentClause(const Token & variable)
        : _variable(variable)
    {
    }
private:
    const Token & _variable;
};

class TopClause: public Clause
{
public:
    TopClause(const Token & count)
        : _count(count)
    {
    }
private:
    const Token & _count;
};

class Column: public Node
{
public:
    Column(const ColumnExpression * expression)
        : _expression(expression)
    {
    }
    virtual ~Column()
    {
        FreeAndNull(_expression);
    }
private:
    const ColumnExpression * _expression;
};

class ColumnWithAlias:public Column
{
public:
    ColumnWithAlias(const ColumnExpression * expression, const Token & alias)
        :Column(expression), _alias(alias)
    {
    }
private:
    const Token & _alias;
};

class SelectContentClause: public Clause
{
public:
    SelectContentClause(const std::vector<Column *> * columns)
        : _columns(columns)
    {
    }
    ~SelectContentClause()
    {
        FreeAndNull(_columns);
    }
private:
    const std::vector<Column *> * _columns;
};

class FromClause: public Clause
{
public:
private:
};

class FromStreamClause: public FromClause
{
public:
    FromStreamClause(const Token & stream)
        : _stream(stream)
    {
    }

private:
    const Token & _stream;
};

class FromVariableClause: public FromClause
{
public:
    FromVariableClause(const Token & variable)
        : _variable(variable)
    {
    }
private:
    const Token & _variable;
};

class FromVariableWithAliasClause: public FromVariableClause
{
public:
    FromVariableWithAliasClause(const Token & variable, const Token & alias)
        : FromVariableClause(variable), _alias(alias)
    {
    }
private:
    const Token & _alias;
};

class WhereClause: public Clause
{
public:
    WhereClause(const BooleanExpression * expression)
        : _expression(expression)
    {
    }
    ~WhereClause()
    {
        FreeAndNull(_expression);
    }
private:
    const BooleanExpression * _expression;
};

class OrderByItem
{
public:
    enum OrderType { ASC, DESC };

    OrderByItem(const Token & column, OrderType order)
        : _column(column), _order(order)
    {
    }
private:
    OrderType _order;
    const Token & _column;
};

class OrderByClause: public Clause
{
public:
    OrderByClause(std::vector<OrderByItem *> * items)
        : _items(items)
    {
    }

    ~OrderByClause()
    {
        if (_items)
        {
            for(auto it = _items->begin(); it!= _items->end(); ++it)
            {
                delete *it;
            }
            delete _items;
            _items = NULL;
        }
    }
private:
    std::vector<OrderByItem *> * _items;
};

class Statement: public Node
{
public:
private:
};

class SelectStatement: public Statement
{
public:
    enum DistinctType { NONE_DISTINCT, DISTINCT };

    SelectStatement(const AssignmentClause * assignment,
        const TopClause * top,
        DistinctType distinctType,
        const SelectContentClause * selectContent,
        const FromClause * from,
        const WhereClause * where,
        const OrderByClause * orderby
        )
        : _assignment(assignment), _top(top), _distinctType(distinctType), _selectContent(selectContent), _from(from),
        _where(where), _orderby(orderby)
    {}

    ~SelectStatement()
    {
        FreeAndNull(_assignment);
        FreeAndNull(_top);
        FreeAndNull(_selectContent);
        FreeAndNull(_from);
        FreeAndNull(_where);
        FreeAndNull(_orderby);
    }

private:
    const AssignmentClause * _assignment;
    const TopClause * _top;
    DistinctType _distinctType;
    const SelectContentClause * _selectContent;
    const FromClause * _from;
    const WhereClause * _where;
    const OrderByClause * _orderby;
};